package gnssio

import (
	"bytes"
	"crypto/rsa"
	"dgo/goutils/cryptoutils"
	"dgo/goutils/utils"
	"fmt"
	"gitee.com/ymofen/supervalue"
	"net/url"
	"strings"
)

type CommRSAEncrptPublic struct {
	listeners *utils.SafeList
	stopflag  uint8

	//0: 加密Send数据, 然后向inner_comm输出数据
	//1: 加密inner_comm 输入数据, 然后分发给listener
	encrpt_flag int

	inner_data_comm I_Comm

	blocksize int
	publicKey *rsa.PublicKey
}

func NewCommRSAEncrptPublic() *CommRSAEncrptPublic {
	rval := &CommRSAEncrptPublic{
		listeners: utils.NewSafeList(),
	}
	return rval
}

/*
**

	rsa-en-pub://publickey/0/ntripsvr://xxx:xxx
	  Send发送数据时, 进行加密,然后使用 ntripsvr协议发出

	rsa-en-pub://publickey/0/COMM_CMD_LINE
	  COMM_CMD_LINE like tcp://ip:port[/tagstr]
	0: 加密Send数据, 然后向inner_comm输出数据
	1: 加密inner_comm 输入数据
*/
func NewCommRSAEncrptPublicFromCmd(cmdstr string) (rval *CommRSAEncrptPublic, err error) {
	ok, cmdstr := utils.CheckTrimPrefix(cmdstr, "rsa-en-pub://")
	if !ok {
		return nil, nil
	}

	if len(cmdstr) == 0 {
		err = fmt.Errorf("缺少配置参数")
		return
	}

	strs := strings.SplitN(cmdstr, "/", 3)
	if len(strs) < 3 {
		err = fmt.Errorf("缺少配置参数(%s)", cmdstr)
		return
	}

	cmdstr = strs[2]
	innercomm, _ := CreateCommFromCmdLine(cmdstr)
	if innercomm == nil {
		err = fmt.Errorf("缺少INNERCOMM(%s)", cmdstr)
		return
	}

	escapstr, _ := url.QueryUnescape(strs[0])

	rval = NewCommRSAEncrptPublic()
	err = rval.SetPublicKey(escapstr)
	if err != nil {
		return nil, fmt.Errorf("rsa(%s) key异常:%s", escapstr, err.Error())
	}
	rval.SetInnerDataComm(innercomm)
	rval.encrpt_flag = utils.StrToIntDef(strs[1], 0)
	return
}

func CreateCommRSAEncrptPublicFunc(args ...interface{}) (rval interface{}, err error) {
	if len(args) < 1 {
		return NewCommRSAEncrptPublic(), nil
	}

	if cmdstr, ok := args[0].(string); ok {
		rval, err = NewCommRSAEncrptPublicFromCmd(cmdstr)
		return
	}

	robj := NewCommRSAEncrptPublic()
	return robj, nil
}

func (this *CommRSAEncrptPublic) SetInnerDataComm(data_comm I_Comm) {
	if this.inner_data_comm != data_comm {
		if this.inner_data_comm != nil {
			this.inner_data_comm.RemoveListener(this)
		}
		this.inner_data_comm = data_comm
		this.inner_data_comm.AddListener(this)
	}
}

func (this *CommRSAEncrptPublic) dispatchBuffer(buf []byte, len int) {
	this.listeners.ForEach(func(val interface{}) {
		val.(I_CommListener).OnReceive(this, buf, len)
	})
}

func (this *CommRSAEncrptPublic) SetPublicKey(keybase64 string) error {
	key, err := cryptoutils.RSA_Base642PublicKey(keybase64)
	if err != nil {
		return fmt.Errorf("非法的PublicKey参数:%s", err.Error())
	}

	this.publicKey = key
	this.blocksize = key.Size() - 11
	return nil
}

func (this *CommRSAEncrptPublic) SetConfig(conf *wrapper.SuperValue) error {
	pubkey := conf.StringByName("publickey", "")
	if len(pubkey) == 0 {
		return fmt.Errorf("缺少publickey参数!")
	}
	return this.SetPublicKey(pubkey)
}

// 分发加密后的数据
func (this *CommRSAEncrptPublic) AddListener(event I_CommListener) {
	if this.listeners.Exists(event) {
		utils.Log.Warn("I_CommListener已经存在请勿重复侦听")
		return
	}
	this.listeners.Add(event)
}

func (this *CommRSAEncrptPublic) RemoveListener(event I_CommListener) {
	this.listeners.Remove(event)
}

func (this *CommRSAEncrptPublic) processBufOnRecv(buf []byte) {

	cipherBuf, err := cryptoutils.RSA_EncryptPublicKey(buf, this.publicKey)
	if err != nil {
		utils.Log.WarnTypef("RSA", "加密Buf失败:[%d]%s", len(buf), utils.BufToHexStr(buf, 0, " "))
	} else {
		this.dispatchBuffer(cipherBuf, len(cipherBuf))
	}

}

func (this *CommRSAEncrptPublic) processBufOutput(buf []byte) int {
	cipherBuf, err := cryptoutils.RSA_EncryptPublicKey(buf, this.publicKey)
	if err != nil {
		utils.Log.WarnTypef("RSA", "加密Buf失败:[%d]%s", len(buf), utils.BufToHexStr(buf, 0, " "))
		return 0
	} else {
		return this.inner_data_comm.Send(cipherBuf, len(cipherBuf))
	}
}

// ======= I_CommListener 侦听内部COMM的数据, 需要进行加密的数据
func (this *CommRSAEncrptPublic) OnReceive(sender I_Comm, buf []byte, l int) {
	if this.encrpt_flag == 1 {
		if l < this.blocksize {
			this.processBufOnRecv(buf[:l])
			return
		}
		reader := bytes.NewReader(buf[:l])
		blockBuf := make([]byte, this.blocksize)
		for {
			n, err := reader.Read(blockBuf)
			if err != nil {
				this.processBufOnRecv(blockBuf[:n])
			} else {
				break
			}
		}
	} else {
		this.dispatchBuffer(buf, l)
	}
}

func (this *CommRSAEncrptPublic) OnConnect(sender I_Comm) {
	this.stopflag = 0
}

func (this *CommRSAEncrptPublic) OnDisconnect(sender I_Comm) {
	this.stopflag = 1
}

// =================================================================
func (this *CommRSAEncrptPublic) Start() {
	if this.inner_data_comm != nil {
		this.inner_data_comm.Start()
	}
}

func (this *CommRSAEncrptPublic) Stop() {
	if this.inner_data_comm != nil {
		this.inner_data_comm.Stop()
	}
}

func (this *CommRSAEncrptPublic) Send(buf []byte, l int) int {
	if this.encrpt_flag == 0 {
		if l < this.blocksize {
			return this.processBufOutput(buf[:l])
		}

		sendBuf := make([]byte, 0, 1024)
		reader := bytes.NewReader(buf[:l])
		blockBuf := make([]byte, this.blocksize)
		for {
			n, err := reader.Read(blockBuf)
			if err == nil {
				cipherBuf, err := cryptoutils.RSA_EncryptPublicKey(blockBuf[:n], this.publicKey)
				if err != nil {
					utils.Log.WarnTypef("RSA", "加密Buf失败:[%d]%s", len(buf), utils.BufToHexStr(buf, 0, " "))
					return 0
				}
				sendBuf = append(sendBuf, cipherBuf...)
			} else {
				break
			}
		}
		return this.inner_data_comm.Send(sendBuf, len(sendBuf))
	} else {
		return this.inner_data_comm.Send(buf, l)
	}
}
